package game;

import heroes.Hero;
import heroes.HeroDisplayer;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.SynchronousQueue;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

import cards.Range;

public class Square extends JPanel implements MouseListener {
	BattleField myBattleField;

	/**
	 * @return "x.y"
	 */
	@Override
	public String toString() {
		return location.x + "." + location.y;
	}

	// TODO ********************The following three methods will decides wether
	// the player clicked on them********************************************
//
//	@Override
//	public boolean contains(int arg0, int arg1) {
//		// TODO Auto-generated method stub
//		return super.contains(arg0, arg1);
//	}

	Border clickableBorder = BorderFactory.createRaisedBevelBorder();
	Border activatedBorder = BorderFactory.createLineBorder(Color.white);
	Border clickedBorder = BorderFactory.createLoweredBevelBorder();

	// all the custom painting should be done within paintComponent()
	// @Override
	// public void paintComponent(Graphics g) {
	// super.paintComponent(g);
	// if (!empty) {
	// occupier.display(g);
	// }
	// // this will be handled once we add the HeroDisplayer in
	// }

	private boolean clickable;
	// TODO visual effects not implemented yet
	public boolean pointedAt;
	private boolean clicked;
	private boolean activated;

	/**
	 * @return the clickable
	 */
	public boolean isClickable() {
		return clickable;
	}

	/**
	 * @return the clicked
	 */
	public boolean isClicked() {
		return clicked;
	}

	/**
	 * @return the activated
	 */
	public boolean isActivated() {
		return activated;
	}

	/**
	 * @param clickable
	 *            the clickable to set
	 */
	public void setClickable(boolean clickable) {
		this.clickable = clickable;
		resetBorder();
		revalidate();
		repaint();
	}

	/**
	 * @param clicked
	 *            the clicked to set
	 */
	public void setClicked(boolean clicked) {
		this.clicked = clicked;
		resetBorder();
		revalidate();
		repaint();
	}

	/**
	 * @param activated
	 *            the activated to set
	 */
	public void setActivated(boolean activated) {
		this.activated = activated;
		resetBorder();
		revalidate();
		repaint();
	}

	private void resetBorder() {
		if (activated) {
			setBorder(activatedBorder);
		} else {
			if (getBorder() == activatedBorder) {
				setBorder(null);
			}
		}
		if (clickable) {
			setBorder(clickableBorder);
		}
		if (clicked) {
			setBorder(clickedBorder);
		}
		if (!clickable) {
			setBorder(null);
		}
	}

	public static int SQUARE_WIDTH;
	public static int SQUARE_HEIGHT;
	public static int BLANK_EDGE;
	public static int PROGRESS_X;
	public static int PROGRESS_Y;

	public static void initPreferredSize() {
		BLANK_EDGE = 0;
		SQUARE_WIDTH = BattleField.BATTLE_FIELD_WIDTH / 4;
		SQUARE_HEIGHT = BattleField.BATTLE_FIELD_HEIGHT / 4;
		System.out.println("SQUARE_WIDTH " + SQUARE_WIDTH);
		System.out.println("SQUARE_HEIGHT " + SQUARE_HEIGHT);
		PROGRESS_X = BLANK_EDGE;
		PROGRESS_Y = SQUARE_HEIGHT - Progress.PROGRESS_HEIGHT;
	}

	// location
	public Range location;

	public int getXcoo() {
		return location.getX();
	}

	public int getYcoo() {
		return location.getY();
	}

	public boolean empty;
	public Hero occupier;

	public void removeOccupier() {
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				empty = true;
				occupier = null;
				if (myHeroDisplayer != null) {
					remove(myHeroDisplayer);
				}
				revalidate();
				repaint();
			}
		});
	}

	public void setOccupier(Hero occupier) {
		if (occupier == null) {
			removeOccupier();
		} else {
			empty = false;
			this.occupier = occupier;
			myHeroDisplayer = occupier.myDisplayer;
			SwingUtilities.invokeLater(new Runnable() {

				@Override
				public void run() {
					add(myHeroDisplayer, BorderLayout.CENTER);
					revalidate();
					repaint();
				}
			});
		}

	}

	// type of field:
	// Court/ Vagabond/ hermit
	static enum Type {
		court, vagabond, hermit;
	}

	private Type myType;
	/**
	 * @return the myType
	 */
	public Type getMyType() {
		return myType;
	}
	// States:
	// the picture will change according to the state of this square
	// static enum State {
	// intoxicated, hypnotized, bleeding, weak, blind, mute, lame, no;
	// }

	// there is only one state that could be the myState
	// private State myState;
	//
	// /**
	// * @return the myState
	// */
	// public State getMyState() {
	// return myState;
	// }

	/**
	 * @param myState
	 *            the myState to set
	 */
	// public void setMyState(State myState) {
	// this.myState = myState;
	// }

	// public void infectOccupier() {
	// switch (getMyState()) {
	// case intoxicated:
	// occupier.setIntoxicated();
	// break;
	// case hypnotized:
	// occupier.setHypnotized();
	// break;
	// case bleeding:
	// occupier.setBleeding();
	// break;
	// case weak:
	// occupier.setWeak();
	// break;
	// case blind:
	// occupier.setBlind();
	// break;
	// case mute:
	// occupier.setMute();
	// break;
	// case lame:
	// occupier.setLame();
	// break;
	// default:
	// // no infection
	// break;
	// }
	// }

	public Square(int x, int y, Type myType, BattleField toBlink) {
		setPreferredSize(new Dimension(SQUARE_WIDTH, SQUARE_HEIGHT));
		setLayout(new BorderLayout());
		location = new Range(x, y);
		// set in BattleField.BattleField()
		// setLocation((x - 1) * SQUARE_WIDTH, (y - 1) * SQUARE_HEIGHT);
		this.myType = myType;
		occupier = null;
		empty = true;
		myBattleField = toBlink;
		addMouseListener(this);
	}

	HeroDisplayer myHeroDisplayer;

	public void occupierChange(Hero newOccupier) {
		occupier = newOccupier;
		add((myHeroDisplayer = occupier.myDisplayer));
		empty = false;
	}

	public void occupierRemove() {
		if (isActivated()) {
			setActivated(false);
		}
		remove(myHeroDisplayer);
		myHeroDisplayer = null;
		occupier = null;
		empty = true;
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		if (clickable) {
			reportClick();
		}
	}

	private void reportClick() {
		myBattleField.squareClicked(this);

	}

	@Override
	public void mouseEntered(MouseEvent e) {
		pointedAt = true;// TODO if this is true, then make there a yellow brink
							// of this square
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		pointedAt = false;
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	Progress myProgress = null;
	boolean progressStarted;

	public void removeProgress(){
		// System.out.println("Square.removeProgress()");
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
//				System.out.println("%%%	remove(myProgress);");
				if (myProgress == null) {
					return;
				}
				if (myProgress != null) {
					revalidate();
					repaint();
					try {
						myProgress.finish();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}finally{
						remove(myProgress);
						myProgress = null;
					}
				}
			}
		});
	}

	public void addProgress() {
//		try {
//			Progress.progressLock.lock();
//		} catch (InterruptedException e) {
//			//  Auto-generated catch block
//			e.printStackTrace();
//		}
//		System.out.println("Square.addProgress()");
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				myProgress = new Progress(PROGRESS_X, PROGRESS_Y, Square.this);
				add(myProgress, BorderLayout.SOUTH);
				revalidate();
				repaint();
			}
		});
//		Progress.progressLock.unlock();

		return;
	}



//	public void addProgress(final View myView) {
////		try {
////			Progress.progressLock.lock();
////		} catch (InterruptedException e) {
////			// TODO Auto-generated catch block
////			e.printStackTrace();
////		}
//
//		System.out.println("Square.addProgress()");
//		SwingUtilities.invokeLater(new Runnable() {
//			@Override
//			public void run() {
//				myProgress = new Progress(PROGRESS_X, PROGRESS_Y, myView, Square.this);
//				add(myProgress, BorderLayout.SOUTH);
//				revalidate();
//				repaint();
//			}
//		});
////		Progress.progressLock.unlock();
//
//		return;
//	}

}
